package com.jmazgaj.satel;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.jmazgaj.satel.utils.CRCUtils;


public class SatelIntegra {
	private InputStream inputStream;
	private OutputStream outputStream;
	
	
	public SatelIntegra(InputStream inputStream, OutputStream outputStream) {
		this.inputStream = inputStream;
		this.outputStream = outputStream;
	}

	
	public void executeCommand(SatelCommand<?> command) throws IOException {
		sendRequest(command);
		
		byte[] response = readResponse(command); 
		
		command.setResponse(response);
	}
	
	
	
	private void sendRequest(SatelCommand<?> command) throws IOException {
		byte [] request = command.createRequest();
		outputStream.write(request);
	}

	private byte[] readResponse(SatelCommand<?> command) throws IOException {
		readStart();
		int actionRead = readByte();

		if (actionRead != command.getActionCode()) {
			throw new IOException("Wrong action code");
		}
		
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		for(int i = 0; i < command.getResponseDataLength(); i++) {
			out.write(readByte());
		}		
		
		int crc1 = readByte();
		int crc2 = readByte();
		int crcRead = (crc1 << 8) + crc2;

		int crcCalculated = CRCUtils.calculateCRC(actionRead, out.toByteArray());
		
		if (crcCalculated != crcRead) {
			throw new IOException("Wrong CRC");			
		}
		
		if (readByte() != 0xFE) {
			throw new IOException("Wrong end message");
		}
		
		if (readByte() != 0x0D) {
			throw new IOException("Wrong end message");
		}
				
		return out.toByteArray();
	}
	
	
	private void readStart() throws IOException {
		boolean firstStart = false;
		
		for(int i = 0; i < 30; i++) {
			int b = readByte();
			if (firstStart) {
				if (b == 0xFE) {
					return;
				} else {
					firstStart = false;
				}
			}
			if (!firstStart && (b == 0xFE)) {
				firstStart = true;
			}
		}
		
		throw new IOException("No start sequence");
	}
		
	private int readByte() throws IOException {
		for(int i = 0; i < 200; i++) {
			int b = inputStream.read();
			if (b == -1) {
				try {Thread.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}
			} else {
				return b;
			}
		}
		
		throw new IOException("Timeout while reading data");
	}
	
}
